home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Networking / OTPingSample / OTPingSample.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  6.6 KB  |  283 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:                OTPingSample.c
  3.  
  4.     Contains:        A trivial ping implementation.
  5.  
  6.     Written by: Quinn "The Eskimo!"    
  7.  
  8.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                             You may incorporate this Apple sample source code into your program(s) without
  11.                             restriction. This Apple sample source code has been provided "AS IS" and the
  12.                             responsibility for its operation is yours. You are not permitted to redistribute
  13.                             this Apple sample source code as "Apple sample source code" after having made
  14.                             changes. If you're going to re-distribute the source, we require that you make
  15.                             it clear in the source that the code was descended from Apple sample source
  16.                             code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                             7/23/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23. #include <stdio.h>
  24. #include <OpenTransport.h>
  25. #include <OpenTptInternet.h>
  26. #include <string.h>
  27. #include <Events.h>
  28.  
  29. /////////////////////////////////////////////////////////////////////
  30.  
  31. static UInt16 ChecksumBuffer(UInt16* buf, size_t len)
  32. {
  33.     // This checksum implementation requires the buffer to be an even number of bytes long.
  34.     UInt32 sum;
  35.     size_t nwords;
  36.     
  37.     nwords = len / 2;
  38.     sum = 0;
  39.     while (nwords > 0) {
  40.         sum += *buf;
  41.         buf++;
  42.         nwords -= 1;
  43.     }
  44.     sum = (sum >> 16 ) + (sum & 0xffff);
  45.     sum += (sum >> 16);
  46.  
  47.     return ~sum;
  48. }
  49.  
  50. /////////////////////////////////////////////////////////////////////
  51.  
  52. static OSStatus CreateAndConfigICMP(EndpointRef *ep)
  53. {
  54.     OSStatus err;
  55.     
  56.     *ep = OTOpenEndpoint(OTCreateConfiguration(kRawIPName), 0, nil, &err);
  57.     
  58.     if (err == noErr) {
  59.     err = OTBind(*ep, nil, nil);
  60.     
  61.         // no others options to negotiate at this stage
  62.         
  63.         // You might think we need to negotiate the XTI_GENERIC/XTI_PROTOTYPE
  64.         // option to request ICMP packets (ie protocol 2).  This is not
  65.         //  necessary because rawip endpoints default to that protocol.
  66.     }
  67.     
  68.     return (err);
  69. }
  70.  
  71. /////////////////////////////////////////////////////////////////////
  72.  
  73. static OSStatus LookupName(InetSvcRef inet_services, char *host_name, InetHost *host_addr)
  74. {
  75.     OSStatus err;
  76.     InetHostInfo response;
  77.     
  78.     memset(&response, 0, sizeof(response));
  79.     
  80.     err = OTInetStringToAddress(inet_services, host_name, &response);
  81.     
  82.     if (err == noErr) {
  83.         *host_addr = response.addrs[0];
  84.     }
  85.  
  86.     return (err);
  87. }
  88.  
  89. /////////////////////////////////////////////////////////////////////
  90.  
  91. enum {
  92.     kOurMagic = 'Quin'
  93. };
  94.  
  95. struct PingPacket {
  96.     UInt8   pType;
  97.     UInt8   pCode;
  98.     UInt16  pChecksum;
  99.     UInt16  pID;
  100.     UInt16  pSeqNum;
  101.     OSType    pMagic;
  102. };
  103. typedef struct PingPacket PingPacket, *PingPacketPtr;
  104.  
  105. /////////////////////////////////////////////////////////////////////
  106.  
  107. static OSStatus SendICMP(EndpointRef ep, InetHost dest, UInt16 seq_number)
  108. {
  109.     OSStatus err;
  110.     InetAddress dest_addr;
  111.     TUnitData udata;
  112.     PingPacket ping_data;
  113.  
  114.     OTInitInetAddress(&dest_addr, 0, dest);        
  115.  
  116.     ping_data.pType = 8;
  117.     ping_data.pCode = 0;
  118.     ping_data.pChecksum = 0;        // dummy checksum of 0 for purposes of checksum calculation
  119.     ping_data.pID = 666;
  120.     ping_data.pSeqNum = seq_number;
  121.     ping_data.pMagic = kOurMagic;
  122.  
  123.     ping_data.pChecksum = ChecksumBuffer((UInt16 *) &ping_data, sizeof(ping_data));
  124.  
  125.     udata.addr.len = sizeof(dest_addr);
  126.     udata.addr.buf = (unsigned char *) &dest_addr;
  127.     
  128.     udata.opt.len = 0;
  129.     udata.opt.buf = nil;
  130.     
  131.     udata.udata.len = sizeof(ping_data);
  132.     udata.udata.buf = (UInt8 *) &ping_data;
  133.  
  134.     err = OTSndUData(ep, &udata);
  135.  
  136.     return (err);
  137. }
  138.  
  139. /////////////////////////////////////////////////////////////////////
  140.  
  141. // we use this buffer to hold incoming ICMP packets
  142.  
  143. static UInt8 icmp_data[5000];
  144.  
  145. /////////////////////////////////////////////////////////////////////
  146.  
  147. static OSStatus WaitAndPrintICMPs(EndpointRef ep, UInt16 seq_number, Boolean *got_response)
  148. {
  149.     TUnitData udata;
  150.     long start_time;
  151.     OSStatus err;
  152.     InetAddress src_addr;
  153.     PingPacketPtr ping_data_ptr;
  154.     
  155.     *got_response = false;
  156.  
  157.     start_time = TickCount();
  158.     
  159.     // Wait for 5 seconds and print out any ICMP packets we get back.
  160.     
  161.     do {
  162.  
  163.         // Set up the received...
  164.         
  165.         udata.addr.buf = (UInt8*) &src_addr;
  166.         udata.addr.maxlen = sizeof(struct InetAddress);
  167.         udata.opt.buf = nil;
  168.         udata.opt.maxlen = 0;
  169.         udata.udata.buf = icmp_data;
  170.         udata.udata.maxlen = sizeof(icmp_data);
  171.         
  172.         // Look for a packet...
  173.         
  174.         err = OTRcvUData(ep, &udata, nil);
  175.         if (err == noErr) {
  176.             // Print out salient information from the packet...
  177.             printf("•••Got ICMP!•••\n");
  178.             
  179.             printf("ICMP from = %d.%d.%d.%d\n", icmp_data[12], icmp_data[13], icmp_data[14], icmp_data[15]);
  180.  
  181.             ping_data_ptr = (PingPacketPtr) &icmp_data[20];
  182.             
  183.             printf("ICMP type = %d\n", ping_data_ptr->pType);
  184.             printf("ICMP code = %d\n", ping_data_ptr->pCode);
  185.             
  186.             if (ping_data_ptr->pType == 0
  187.                             && ping_data_ptr->pID == 666 
  188.                             && ping_data_ptr->pSeqNum == seq_number 
  189.                             && ping_data_ptr->pMagic == kOurMagic) {
  190.                 *got_response = true;
  191.             }
  192.             
  193.             fflush(stdout);
  194.         } else if (err == kOTNoDataErr) {
  195.             err = noErr;
  196.         }
  197.     } while (err == noErr && TickCount() < start_time + 5 * 60);
  198.  
  199.     return (err);
  200. }
  201.  
  202. /////////////////////////////////////////////////////////////////////
  203.  
  204. static OSStatus DoPing(InetHost dest)
  205. {
  206.     OSStatus err;
  207.     EndpointRef icmp_ep = nil;
  208.     UInt16 seq_number;
  209.     UInt16 lost;
  210.     Boolean got_response;
  211.     
  212.     // Create the endpoint and negotiate the options...
  213.     err = CreateAndConfigICMP(&icmp_ep);
  214.     
  215.     // Do the main ping loop...
  216.     
  217.     seq_number = 0;
  218.     lost = 0;
  219.     do {
  220.         printf("\nSending ping...\n");
  221.         err = SendICMP(icmp_ep, dest, seq_number);
  222.         if (err == noErr) {
  223.             err = WaitAndPrintICMPs(icmp_ep, seq_number, &got_response);
  224.         }
  225.         if (err == noErr) {
  226.             if (!got_response) {
  227.                 lost += 1;
  228.             }
  229.             seq_number += 1;
  230.         }
  231.     } while (err == noErr && seq_number < 5);
  232.  
  233.     if (err == noErr) {
  234.         printf("Ping complete.  %d packets sent.  %d packets lost.  %d%% packet loss.\n", seq_number, lost, lost * 100 / seq_number);
  235.     }
  236.  
  237.     // clean up
  238.     if (icmp_ep != nil) {
  239.         (void) OTCloseProvider(icmp_ep);
  240.     }
  241.     return err;
  242. }
  243.  
  244. /////////////////////////////////////////////////////////////////////
  245.  
  246. void main(void) {
  247.     OSStatus err;
  248.     char host_name[256];
  249.     InetHost host_addr;
  250.     InetSvcRef inet_services = nil;
  251.     
  252.     printf("Hello Cruel World!\n");
  253.     
  254.     err = InitOpenTransport();
  255.     
  256.     if (err == noErr) {
  257.         inet_services = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err);
  258.         
  259.         if (err == noErr) {
  260.             printf("Enter name of host to ping:\n");
  261.             gets(host_name);
  262.             
  263.             err = LookupName(inet_services, host_name, &host_addr);
  264.         }
  265.         
  266.         if (err == noErr) {
  267.             err = DoPing(host_addr);
  268.         }
  269.  
  270.         if (inet_services != nil) {
  271.             OTCloseProvider(inet_services);
  272.         }
  273.     
  274.         CloseOpenTransport();
  275.     }
  276.     
  277.     if (err == noErr) {
  278.         printf("Success!\n");
  279.     } else {
  280.         printf("Failure!  Error = %d.\n", err);
  281.     }
  282.     printf("Done.  Press command-Q to Quit.\n");
  283. }